
module Pattern
  module Contract

    def self.enable klass, &block
      klass.class_eval {
        def self.contract &block
          ::Pattern::Contract.set(self, &block)

          contract = Module.new(&block)
          (contract.instance_methods - Module.new.instance_methods).each { |m|
            send(:alias_method, 'old_'+m.to_s, m)
            send(:remove_method, m)
          }
          send(:include, contract)
        end
      }
    end

    def self.set klass, &block
      (@@contracts ||= {})[klass] = block
    end

    def self.for klass
      Class.new(klass, &@@contracts[klass])
    end
  end
end


class MyClass

  Pattern::Contract.enable(self)

  def a
    "A"
  end

  contract {
    def a
      "MMM"+old_a
    end
  }

end


p MyClass.new.a == "MMMA"
puts "(#{MyClass.new.a})"


p Pattern::Contract.for(MyClass).new.a == "MMMA"
